#include <sys_head.h>
#include "tcp.h"
#include "list.h"

// 多进程 TCP 服务器

// 共享内存用定义
#define SHM_MAX_SIZE 16384
#define SHM_KEY 1234
#define SEM_KEY 12345

User_list *shm_init(void);

// 信号量加锁
void My_Sem_wait(int semid);

// 信号量解锁
void My_Sem_signal(int semid);

// 处理SIGCHLD信号，防止僵尸进程
void handle_sigchld(int sig);

// 子进程处理函数
void handle_client(int Sock_fd, User_list *list, int semid);

int main(int argc, char const *argv[])
{
    // 判断命令行参数
    if (argc < 2)
    {
        printf("参数错误:%s ip port\n", argv[0]);
        return -1;
    }

    /********************* 初始化TCP 服务器 *********************/

    int Sock_server_fd = TCP_init(atoi(argv[1]));

    /*********************** 初始化共享内存 **********************/
    User_list *User_list_ptr = shm_init();

    /*********************** 初始化信号灯集 **********************/
    int semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);
    semctl(semid, 0, SETVAL, 1); // 初始化信号量值为 1

    /*********************** 注册处理僵尸进程 **********************/
    signal(SIGCHLD, handle_sigchld);

    /*********************** 声明收发缓冲区 **********************/
    char buf_send[1024];
    char buf_recv[1024];

    while (1)
    {
        int Sock_client_fd = TCP_accept(Sock_server_fd);

        // 创建进程
        pid_t client_pid = fork();
        if (0 == client_pid) // 子进程
        {
            // 关闭父进程的套接字
            close(Sock_server_fd); // 关闭父进程的套接字

            // 子进程操作函数
            handle_client(Sock_client_fd, User_list_ptr, semid);

            shmdt(User_list_ptr);

            exit(-1);
        }
        else if (0 < client_pid) // 父亲进程
        {

            My_Sem_wait(semid); // 加锁

            // 将新的连接添加到链表中
            User_list_ptr->data[User_list_ptr->len].Sock_fd = Sock_client_fd;

            sprintf(buf_send, "%s|fd:%d|id:%d", "新用户", Sock_client_fd, User_list_ptr->len);

            strcpy(User_list_ptr->data[User_list_ptr->len].name, buf_send);

            send(Sock_client_fd, buf_send, strlen(buf_send), 0);

            User_list_ptr->len++;

            // 关闭子进程的文件描述符
            // close(Sock_client_fd);

            My_Sem_signal(semid); // 解锁
        }
    }
    shmdt(User_list_ptr);

    //  7、关闭套接字  close
    close(Sock_server_fd);
    return 0;
}

// 初始化共享内存
User_list *shm_init(void)
{
    int shmid;

    // 创建一个共享内存段，权限为 0666
    shmid = shmget(SHM_KEY, SHM_MAX_SIZE, 0666 | IPC_CREAT);
    if (shmid == -1)
    {
        perror("shmget 创建共享内存段失败");
        exit(EXIT_FAILURE);
    }

    printf("共享内存段创建成功,ID: %d\n", shmid);

    // 附加共享内存
    User_list *user_list_ptr = (User_list *)shmat(shmid, NULL, 0);
    if (user_list_ptr == (User_list *)-1)
    {
        perror("shmat failed");
        exit(1);
    }
    // 打印指针的地址
    printf("附加共享内存成功, 地址: %p\n", user_list_ptr);

    // 清空共享内存
    memset(user_list_ptr, 0, sizeof(User_list));

    // 初始化顺序表
    user_list_ptr->len = 0;

    return user_list_ptr;
}

// 处理SIGCHLD信号，防止僵尸进程
void handle_sigchld(int sig)
{
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ; // 非阻塞等待子进程结束
}

// 信号量加锁
void My_Sem_wait(int semid)
{
    struct sembuf sb = {0, -1, 0};
    semop(semid, &sb, 1);
}

// 信号量解锁
void My_Sem_signal(int semid)
{
    struct sembuf sb = {0, 1, 0};
    semop(semid, &sb, 1);
}

// 子进程处理函数
void handle_client(int Sock_fd, User_list *list, int semid)
{
    // 收发缓冲区
    char buf_send[2048];
    char buf_recv[1024];

    // 计算当前进程所在顺序表的位置
    My_Sem_wait(semid); // 加锁
    int index = 0;
    for (size_t i = 0; i < list->len; i++)
    {
        if (Sock_fd == list->data[i].Sock_fd)
        {
            index = i;
        }
    }
    My_Sem_signal(semid); // 解锁

    while (1)
    {
        memset(buf_send, 0, sizeof(buf_send));
        memset(buf_recv, 0, sizeof(buf_recv));

        int recv_size = recv(Sock_fd, buf_recv, sizeof(buf_recv), 0);
        if (0 == recv_size) // 判定退出
        {
            // 从顺序表中删除
            My_Sem_wait(semid); // 加锁

            for (size_t i = index; i < list->len; i++)
            {
                list->data[index] = list->data[index + 1];
            }

            list->len--;

            printf("退出成功....");

            close(Sock_fd);

            My_Sem_signal(semid); // 解锁

            return;
        }

        // 修改名字
        if (NULL != strstr(buf_recv, "set_name_"))
        {
            My_Sem_wait(semid); // 加锁
            // 写入姓名
            strcpy(list->data[index].name, buf_recv + 9);

            sprintf(buf_send, "修改名称成功:%s", list->data[index].name);

            send(Sock_fd, buf_send, strlen(buf_send), 0);

            My_Sem_signal(semid); // 解锁

            continue;
        }

        // 转发 群发
        else
        {
            // 组装字符串
            sprintf(buf_send, "%s : %s", list->data[index].name, buf_recv);

            // 发送给其他成员
            for (size_t i = 0; i < list->len; i++)
            {
                if (Sock_fd != list->data[i].Sock_fd)
                {
                    int result = send(list->data[i].Sock_fd, buf_send, strlen(buf_send), 0);
                    if (result < 0)
                    {
                        perror("发送失败");
                        // 处理发送失败的情况（比如关闭连接、删除用户等）
                    }
                }
            }

            My_Sem_signal(semid); // 解锁
        }
    }
}